#include <p24FJ32GA002.h>
#include <stdio.h>

// EEPROM module i2c address
#define I2C_ADDR_W 0b10100000
#define I2C_ADDR_R 0b10100001

void InitEEPROM(void)
{
  I2C1BRG = 0x0009; // baudrate, Fscl 400 kHz

  // Enables the I2Cx module and configures the SDAx and SCLx pins as serial port pins
  I2C1CONbits.I2CEN = 1;

  I2C1STAT = 0x0000;
}

/*
void _ISR _MI2C1Interrupt(void){

  KnipperLedRood();
  
  // Master I2C1 Event Interrupt Flag Status bit
  IFS1bits.MI2C1IF = 0;		// clear interupt
}//einde interupt
*/

/*********************************************************************
* Function:        StartI2CC_Master()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates an I2C Start Condition
*
* Note:			None
********************************************************************/

unsigned int StartI2C_Master()
{
  //This function generates an I2C start condition and returns status 
  //of the Start.

  I2C1CONbits.SEN = 1;		//Generate Start COndition
  while (I2C1CONbits.SEN);	//Wait for Start COndition
  //return(I2C1STATbits.S);	//Optionally return status

  return(0);
}

/*********************************************************************
* Function:        RestartI2C_Master()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates a restart condition and optionally returns status
*
* Note:			None
********************************************************************/

unsigned int RestartI2C_Master()
{
  //This function generates an I2C Restart condition and returns status 
  //of the Restart.

  I2C1CONbits.RSEN = 1;		//Generate Restart		
  while (I2C1CONbits.RSEN);	//Wait for restart	
  //return(I2C1STATbits.S);	//Optional - return status
  return(0);
}

/*********************************************************************
* Function:        StopI2C_Master()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates a bus stop condition
*
* Note:			None
********************************************************************/

unsigned int StopI2C_Master()
{
  //This function generates an I2C stop condition and returns status 
  //of the Stop.

  I2C1CONbits.PEN = 1;		//Generate Stop Condition
  while (I2C1CONbits.PEN);	//Wait for Stop
  //return(I2C1STATbits.P);	//Optional - return status
  return(0);
}

/*********************************************************************
* Function:        WriteI2C_Master()
*
* Input:		Byte to write.
*
* Output:		None.
*
* Overview:		Writes a byte out to the bus
*
* Note:			None
********************************************************************/

unsigned int WriteI2C_Master(unsigned char byte)
{
  //This function transmits the byte passed to the function
  //while (I2C1STATbits.TRSTAT);	//Wait for bus to be idle
  I2C1TRN = byte;					//Load byte to I2C1 Transmit buffer
  while (I2C1STATbits.TBF);		//wait for data transmission
	return(0);

}

/*********************************************************************
* Function:        IdleI2C_Master()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Waits for bus to become Idle
*
* Note:			None
********************************************************************/

unsigned int IdleI2C_Master()
{
  while (I2C1STATbits.TRSTAT);		//Wait for bus Idle
  return(0);
}

/*********************************************************************
* Function:        ACKStatus_Master()
*
* Input:		None.
*
* Output:		Acknowledge Status.
*
* Overview:		Return the Acknowledge status on the bus
*
* Note:			None
********************************************************************/

unsigned int ACKStatus_Master()
{
  return (!I2C1STATbits.ACKSTAT);		//Return Ack Status
  return(0);
}

/*********************************************************************
* Function:        NotAckI2C_Master()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates a NO Acknowledge on the Bus
*
* Note:			None
********************************************************************/

unsigned int NotAckI2C_Master()
{
  I2C1CONbits.ACKDT = 1;			//Set for NotACk
  I2C1CONbits.ACKEN = 1;
  while(I2C1CONbits.ACKEN);		//wait for ACK to complete
  I2C1CONbits.ACKDT = 0;			//Set for NotACk
  return(0);
}

/*********************************************************************
* Function:        AckI2C_Master()
*
* Input:		None.
*
* Output:		None.
*
* Overview:		Generates an Acknowledge.
*
* Note:			None
********************************************************************/

unsigned int AckI2C_Master()
{
  I2C1CONbits.ACKDT = 0;			//Set for ACk
  I2C1CONbits.ACKEN = 1;
  while(I2C1CONbits.ACKEN);		//wait for ACK to complete
  return(0);
}


/*********************************************************************
* Function:       getsI2C_Master()
*
* Input:		array pointer, Length.
*
* Output:		None.
*
* Overview:		read Length number of Bytes into array
*
* Note:			None
********************************************************************/

int getsI2C_Master(unsigned char *rdptr, unsigned char Length)
{	
  while (Length --)
  {	
  *rdptr++ = getI2C_Master();		//get a single byte
  	
  if(I2C1STATbits.BCL)			//Test for Bus collision
  {	
    return(-1);
  }
  
  if(Length)
  {
    AckI2C_Master();				//Acknowledge until all read
  }
  }
  
  return(0);
}

/*********************************************************************
* Function:        getI2C_Master()
*
* Input:		None.
*
* Output:		contents of I2C1 receive buffer.
*
* Overview:		Read a single byte from Bus
*
* Note:			None
********************************************************************/

int getI2C_Master()
{	
  I2C1CONbits.RCEN = 1;			//Enable Master receive
  Nop();
  while(!I2C1STATbits.RBF);		//Wait for receive bufer to be full
  return(I2C1RCV);				//Return data in buffer
}

int WriteData(char address, char *value) 
{
  int success = 0;						// Succesvol = 1

  IdleI2C_Master();						// Ensure Module is Idle
  StartI2C_Master();					// Generate Start COndition
  WriteI2C_Master(I2C_ADDR_W);			// Write
  IdleI2C_Master();						// wait for bus Idle

  if (ACKStatus_Master())					//Return ACK Status
  {	
	// Wijs adres pointer naar plek waar info opgeslagen moet worden
	WriteI2C_Master(address);	    		// Transmit Word Address 
	IdleI2C_Master();

	if(ACKStatus_Master()) 
   	{
	  IdleI2C_Master();
	  WriteI2C_Master(value);
	  IdleI2C_Master();
	  success = (ACKStatus_Master() ? 1 : -1);
	} 
	else
	{
	  success = -1;
	}
  } 
  else
  {
	success = -1;
  }

  IdleI2C_Master();
  StopI2C_Master();					//Initiate Stop Condition	
}

int ReadData(char address, char *I2C_OutputData) 
{
 
  int success = 0;						// Succesvol = 1

  IdleI2C_Master();						// Ensure Module is Idle
  StartI2C_Master();					// Generate Start COndition
  WriteI2C_Master(I2C_ADDR_W);			// Write
  IdleI2C_Master();						// wait for bus Idle

  if (ACKStatus_Master())				//Return ACK Status
  {	
	// Wijs adres pointer naar plek waar info is opgeslagen
	WriteI2C_Master(address);	    		// Transmit Word Address 
	IdleI2C_Master();
	
	// Restart en begin met lezen
	RestartI2C_Master();				//Generate restart condition
	WriteI2C_Master(I2C_ADDR_R);
	IdleI2C_Master();					//wait for bus Idle

/*  Zo kan het ook, maar dan is er geen collition check
	I2C_OutputData[0] = getI2C_Master();
	AckI2C_Master();	
	I2C_OutputData[1] = getI2C_Master();
	AckI2C_Master();
	I2C_OutputData[2] = getI2C_Master();
*/

	success = getsI2C_Master(&I2C_OutputData[0], 2); //read Length number of bytes
	//success = getsI2C_Master(&I2C_OutputData[0], 1); //read Length number of bytes


	// Einde met N-ACK
	NotAckI2C_Master();					//Send Not Ack
	
	// Als 
	success = (success==0 ? 1 : success);
  }
  else 
  {
	success = -1;
  }

  IdleI2C_Master();
  StopI2C_Master();					//Initiate Stop Condition

/*
  // Test
	putsU1("succes: "); putU1Dec(success); putsU1(", ");	
	putU1Dec(I2C_OutputData[0]); putsU1(", ");	
	putU1Dec(I2C_OutputData[1]); putsU1(", ");	
	putU1Dec(I2C_OutputData[2]);
	PutU1NewLine();	
  // Test
*/

  return success;
}

int WriteSBData() 
{
  int ADC = GetADC_SB(100);
  int success = -1;

  if(ADC < 50) {
	WriteData(14, ADC);
  } else {
	WriteData(15, ADC);
  }

  return ;
}

void ReadSBData(char *I2C_OutputData)
{
 return ReadData(14, I2C_OutputData); 
}

